/**

 @Name：dropdown 下拉菜单组件
 @License：MIT

 */
import $ from 'jquery'
import laytpl from "./laytpl";
import layui from "./layui";

var hint = layui.hint()
	, device = layui.device()
	, clickOrMousedown = (device.mobile ? 'click' : 'mousedown')

	//模块名
	, MOD_NAME = 'dropdown'
	, MOD_INDEX = 'layui_' + MOD_NAME + '_index' //模块索引名

	//外部接口
	, dropdown = {
		config: {}
		, index: layui[MOD_NAME] ? (layui[MOD_NAME].index + 10000) : 0

		//设置全局项
		, set: function (options) {
			var that = this;
			that.config = $.extend({}, that.config, options);
			return that;
		}

		//事件
		, on: function (events, callback) {
			return layui.onevent.call(this, MOD_NAME, events, callback);
		}
	}

	//操作当前实例
	, thisModule = function () {
		var that = this
			, options = that.config
			, id = options.id;

		thisModule.that[id] = that; //记录当前实例对象

		return {
			config: options
			//重置实例
			, reload: function (options) {
				that.reload.call(that, options);
			}
		}
	}

	//字符常量
	, STR_ELEM = 'layui-dropdown', STR_HIDE = 'layui-hide', STR_DISABLED = 'layui-disabled', STR_NONE = 'layui-none'
	, STR_ITEM_UP = 'layui-menu-item-up', STR_ITEM_DOWN = 'layui-menu-item-down',
	STR_MENU_TITLE = 'layui-menu-body-title', STR_ITEM_GROUP = 'layui-menu-item-group',
	STR_ITEM_PARENT = 'layui-menu-item-parent', STR_ITEM_DIV = 'layui-menu-item-divider',
	STR_ITEM_CHECKED = 'layui-menu-item-checked', STR_ITEM_CHECKED2 = 'layui-menu-item-checked2',
	STR_MENU_PANEL = 'layui-menu-body-panel', STR_MENU_PANEL_L = 'layui-menu-body-panel-left'

	, STR_GROUP_TITLE = '.' + STR_ITEM_GROUP + '>.' + STR_MENU_TITLE

	//构造器
	, Class = function (options) {
		var that = this;
		that.index = ++dropdown.index;
		that.config = $.extend({}, that.config, dropdown.config, options);
		that.init();
	};

//默认配置
Class.prototype.config = {
	trigger: 'click' //事件类型
	, content: '' //自定义菜单内容
	, className: '' //自定义样式类名
	, style: '' //设置面板 style 属性
	, show: false //是否初始即显示菜单面板
	, isAllowSpread: true //是否允许菜单组展开收缩
	, isSpreadItem: true //是否初始展开子菜单
	, data: [] //菜单数据结构
	, delay: 300 //延迟关闭的毫秒数，若 trigger 为 hover 时才生效
};

//重载实例
Class.prototype.reload = function (options) {
	var that = this;
	that.config = $.extend({}, that.config, options);
	that.init(true);
};

//初始化准备
Class.prototype.init = function (rerender) {
	var that = this
		, options = that.config
		, elem = options.elem = $(options.elem);

	//若 elem 非唯一
	if (elem.length > 1) {
		layui.each(elem, function () {
			dropdown.render($.extend({}, options, {
				elem: this
			}));
		});
		return that;
	}

	//若重复执行 render，则视为 reload 处理
	if (!rerender && elem[0] && elem.data(MOD_INDEX)) {
		;
		var newThat = thisModule.getThis(elem.data(MOD_INDEX));
		if (!newThat) return;

		return newThat.reload(options);
	}
	;

	//初始化 id 参数
	options.id = ('id' in options) ? options.id : that.index;

	if (options.show) that.render(rerender); //初始即显示
	that.events(); //事件
};

//渲染
Class.prototype.render = function (rerender) {
	var that = this
		, options = that.config
		, elemBody = $('body')

		//默认菜单内容
		, getDefaultView = function () {
			var elemUl = $('<ul class="layui-menu layui-dropdown-menu"></ul>');
			if (options.data.length > 0) {
				eachItemView(elemUl, options.data)
			} else {
				elemUl.html('<li class="layui-menu-item-none">no menu</li>');
			}
			return elemUl;
		}

		//遍历菜单项
		, eachItemView = function (views, data) {
			//var views = [];
			layui.each(data, function (index, item) {
				//是否存在子级
				var isChild = item.child && item.child.length > 0
					, isSpreadItem = ('isSpreadItem' in item) ? item.isSpreadItem : options.isSpreadItem
					, title = item.templet
						? laytpl(item.templet).render(item)
						: (options.templet ? laytpl(options.templet).render(item) : item.title)

					//初始类型
					, type = function () {
						if (isChild) {
							item.type = item.type || 'parent';
						}
						if (item.type) {
							return ({
								group: 'group'
								, parent: 'parent'
								, '-': '-'
							})[item.type] || 'parent';
						}
						return '';
					}();

				if (type !== '-' && (!item.title && !item.id && !isChild)) return;

				//列表元素
				var viewLi = $(['<li' + function () {
					var className = {
						group: 'layui-menu-item-group' + (
							options.isAllowSpread ? (
								isSpreadItem ? ' layui-menu-item-down' : ' layui-menu-item-up'
							) : ''
						)
						, parent: STR_ITEM_PARENT
						, '-': 'layui-menu-item-divider'
					};
					if (isChild || type) {
						return ' class="' + className[type] + '"';
					}
					return '';
				}() + '>'

					//标题区
					, function () {
						//是否超文本
						var viewText = ('href' in item) ? (
							'<a href="' + item.href + '" target="' + (item.target || '_self') + '">' + title + '</a>'
						) : title;

						//是否存在子级
						if (isChild) {
							return '<div class="' + STR_MENU_TITLE + '">' + viewText + function () {
								if (type === 'parent') {
									return '<i class="layui-icon layui-icon-right"></i>';
								} else if (type === 'group' && options.isAllowSpread) {
									return '<i class="layui-icon layui-icon-' + (isSpreadItem ? 'up' : 'down') + '"></i>';
								} else {
									return '';
								}
							}() + '</div>'

						}
						return '<div class="' + STR_MENU_TITLE + '">' + viewText + '</div>';
					}()
					, '</li>'].join(''));

				viewLi.data('item', item);

				//子级区
				if (isChild) {
					var elemPanel = $('<div class="layui-panel layui-menu-body-panel"></div>')
						, elemUl = $('<ul></ul>');

					if (type === 'parent') {
						elemPanel.append(eachItemView(elemUl, item.child));
						viewLi.append(elemPanel);
					} else {
						viewLi.append(eachItemView(elemUl, item.child));
					}
				}

				views.append(viewLi);
			});
			return views;
		}

		//主模板
		, TPL_MAIN = ['<div class="layui-dropdown layui-border-box layui-panel layui-anim layui-anim-downbit">'
			, '</div>'].join('');

	//如果是右键事件，则每次触发事件时，将允许重新渲染
	if (options.trigger === 'contextmenu' || lay.isTopElem(options.elem[0])) rerender = true;

	//判断是否已经打开了下拉菜单面板
	if (!rerender && options.elem.data(MOD_INDEX + '_opened')) return;

	//记录模板对象
	that.elemView = $(TPL_MAIN);
	that.elemView.append(options.content || getDefaultView());

	//初始化某些属性
	if (options.className) that.elemView.addClass(options.className);
	if (options.style) that.elemView.attr('style', options.style);


	//记录当前执行的实例索引
	dropdown.thisId = options.id;

	//插入视图
	that.remove(); //移除非当前绑定元素的面板
	elemBody.append(that.elemView);
	options.elem.data(MOD_INDEX + '_opened', true);

	//坐标定位
	that.position();
	thisModule.prevElem = that.elemView; //记录当前打开的元素，以便在下次关闭
	thisModule.prevElem.data('prevElem', options.elem); //将当前绑定的元素，记录在打开元素的 data 对象中

	//阻止全局事件
	that.elemView.find('.layui-menu').on(clickOrMousedown, function (e) {
		layui.stope(e);
	});

	//触发菜单列表事件
	that.elemView.find('.layui-menu li').on('click', function (e) {
		var othis = $(this)
			, data = othis.data('item') || {}
			, isChild = data.child && data.child.length > 0;

		if (!isChild && data.type !== '-') {
			that.remove();
			typeof options.click === 'function' && options.click(data, othis);
		}
	});

	//触发菜单组展开收缩
	that.elemView.find(STR_GROUP_TITLE).on('click', function (e) {
		var othis = $(this)
			, elemGroup = othis.parent()
			, data = elemGroup.data('item') || {}

		if (data.type === 'group' && options.isAllowSpread) {
			thisModule.spread(elemGroup);
		}
	});

	//如果是鼠标移入事件，则鼠标移出时自动关闭
	if (options.trigger === 'mouseenter') {
		that.elemView.on('mouseenter', function () {
			clearTimeout(thisModule.timer);
		}).on('mouseleave', function () {
			that.delayRemove();
		});
	}

};

//位置定位
Class.prototype.position = function (obj) {
	var that = this
		, options = that.config;

	lay.position(options.elem[0], that.elemView[0], {
		position: options.position
		, e: that.e
		, clickType: options.trigger === 'contextmenu' ? 'right' : null
		, align: options.align || null
	});
};

//删除视图
Class.prototype.remove = function () {
	var that = this
		, options = that.config
		, elemPrev = thisModule.prevElem;

	//若存在已打开的面板元素，则移除
	if (elemPrev) {
		elemPrev.data('prevElem') && (
			elemPrev.data('prevElem').data(MOD_INDEX + '_opened', false)
		);
		elemPrev.remove();
	}
};

//延迟删除视图
Class.prototype.delayRemove = function () {
	var that = this
		, options = that.config;
	clearTimeout(thisModule.timer);

	thisModule.timer = setTimeout(function () {
		that.remove();
	}, options.delay);
};

//事件
Class.prototype.events = function () {
	var that = this
		, options = that.config;

	//如果传入 hover，则解析为 mouseenter
	if (options.trigger === 'hover') options.trigger = 'mouseenter';

	//解除上一个事件
	if (that.prevElem) that.prevElem.off(options.trigger, that.prevElemCallback);

	//记录被绑定的元素及回调
	that.prevElem = options.elem;
	that.prevElemCallback = function (e) {
		clearTimeout(thisModule.timer);
		that.e = e;
		that.render();
		e.preventDefault();

		//组件打开完毕的时间
		typeof options.ready === 'function' && options.ready(that.elemView, options.elem, that.e.target);
	};

	//触发元素事件
	options.elem.on(options.trigger, that.prevElemCallback);

	//如果是鼠标移入事件
	if (options.trigger === 'mouseenter') {
		//直行鼠标移出事件
		options.elem.on('mouseleave', function () {
			that.delayRemove();
		});
	}
};

//记录所有实例
thisModule.that = {}; //记录所有实例对象

//获取当前实例对象
thisModule.getThis = function (id) {
	var that = thisModule.that[id];
	if (!that) hint.error(id ? (MOD_NAME + ' instance with ID \'' + id + '\' not found') : 'ID argument required');
	return that;
};

//设置菜单组展开和收缩状态
thisModule.spread = function (othis) {
	//菜单组展开和收缩
	var elemIcon = othis.children('.' + STR_MENU_TITLE).find('.layui-icon');
	if (othis.hasClass(STR_ITEM_UP)) {
		othis.removeClass(STR_ITEM_UP).addClass(STR_ITEM_DOWN);
		elemIcon.removeClass('layui-icon-down').addClass('layui-icon-up');
	} else {
		othis.removeClass(STR_ITEM_DOWN).addClass(STR_ITEM_UP);
		elemIcon.removeClass('layui-icon-up').addClass('layui-icon-down')
	}
};

//全局事件
;!function () {
	var _WIN = $(window)
		, _DOC = $(document);

	//自适应定位
	_WIN.on('resize', function () {
		if (!dropdown.thisId) return;
		var that = thisModule.getThis(dropdown.thisId);
		if (!that) return;

		if (!that.elemView[0] || !$('.' + STR_ELEM)[0]) {
			return false;
		}

		var options = that.config;

		if (options.trigger === 'contextmenu') {
			that.remove();
		} else {
			that.position();
		}
	});


	//点击任意处关闭
	_DOC.on(clickOrMousedown, function (e) {
		if (!dropdown.thisId) return;
		var that = thisModule.getThis(dropdown.thisId)
		if (!that) return;

		var options = that.config;

		//如果触发的是绑定的元素，或者属于绑定元素的子元素，则不关闭
		//满足条件：当前绑定的元素不是 body document，或者不是鼠标右键事件
		if (!(lay.isTopElem(options.elem[0]) || options.trigger === 'contextmenu')) {
			if (
				e.target === options.elem[0] ||
				options.elem.find(e.target)[0] ||
				e.target === that.elemView[0] ||
				(that.elemView && that.elemView.find(e.target)[0])
			) return;
		}

		that.remove();
	});

	//基础菜单的静态元素事件
	var ELEM_LI = '.layui-menu:not(.layui-dropdown-menu) li';
	_DOC.on('click', ELEM_LI, function (e) {
		var othis = $(this)
			, parent = othis.parents('.layui-menu').eq(0)
			, isChild = othis.hasClass(STR_ITEM_GROUP) || othis.hasClass(STR_ITEM_PARENT)
			, filter = parent.attr('lay-filter') || parent.attr('id')
			, options = lay.options(this);

		//非触发元素
		if (othis.hasClass(STR_ITEM_DIV)) return;

		//非菜单组
		if (!isChild) {
			//选中
			parent.find('.' + STR_ITEM_CHECKED).removeClass(STR_ITEM_CHECKED); //清除选中样式
			parent.find('.' + STR_ITEM_CHECKED2).removeClass(STR_ITEM_CHECKED2); //清除父级菜单选中样式
			othis.addClass(STR_ITEM_CHECKED); //添加选中样式
			othis.parents('.' + STR_ITEM_PARENT).addClass(STR_ITEM_CHECKED2); //添加父级菜单选中样式

			//触发事件
			layui.event(MOD_NAME, 'click(' + filter + ')', options);
		}
	});

	//基础菜单的展开收缩事件
	_DOC.on('click', (ELEM_LI + STR_GROUP_TITLE), function (e) {
		var othis = $(this)
			, elemGroup = othis.parents('.' + STR_ITEM_GROUP + ':eq(0)')
			, options = lay.options(elemGroup[0]);

		if (('isAllowSpread' in options) ? options.isAllowSpread : true) {
			thisModule.spread(elemGroup);
		}
		;
	});

	//判断子级菜单是否超出屏幕
	var ELEM_LI_PAR = '.layui-menu .' + STR_ITEM_PARENT
	_DOC.on('mouseenter', ELEM_LI_PAR, function (e) {
		var othis = $(this)
			, elemPanel = othis.find('.' + STR_MENU_PANEL);

		if (!elemPanel[0]) return;
		var rect = elemPanel[0].getBoundingClientRect();

		//是否超出右侧屏幕
		if (rect.right > _WIN.width()) {
			elemPanel.addClass(STR_MENU_PANEL_L);
			//不允许超出左侧屏幕
			rect = elemPanel[0].getBoundingClientRect();
			if (rect.left < 0) {
				elemPanel.removeClass(STR_MENU_PANEL_L);
			}
		}

		//是否超出底部屏幕
		if (rect.bottom > _WIN.height()) {
			elemPanel.eq(0).css('margin-top', -(rect.bottom - _WIN.height()));
		}
		;
	}).on('mouseleave', ELEM_LI_PAR, function (e) {
		var othis = $(this)
			, elemPanel = othis.children('.' + STR_MENU_PANEL);

		elemPanel.removeClass(STR_MENU_PANEL_L);
		elemPanel.css('margin-top', 0);
	});

}();

//重载实例
dropdown.reload = function (id, options) {
	var that = thisModule.getThis(id);
	if (!that) return this;

	that.reload(options);
	return thisModule.call(that);
};

//核心入口
dropdown.render = function (options) {
	var inst = new Class(options);
	return thisModule.call(inst);
};

export default dropdown;
